﻿using System;
using System.Text;

namespace Sencha.Serialization.Serializers
{
    public sealed class JsonStringSerializer : TypeSerializer<JsonString>
    {
		public static readonly JsonStringSerializer Instance = new JsonStringSerializer();

		public override JsonString Deserialize(IJsonReader reader)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            var jsonStringBuilder = new StringBuilder();
            var isPrimitive = SkipValue(reader, jsonStringBuilder);

            var jsonString = new JsonString(jsonStringBuilder);
            return jsonString;
        }
		public override void Serialize(IJsonWriter writer, JsonString value)
        {
            if (writer == null)
                throw new ArgumentNullException("writer");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            if (value == null)
                writer.WriteNull();
            else
                writer.WriteJson(value.ToString());
        }

        private static bool SkipValue(IJsonReader reader, StringBuilder buffer)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            System.Diagnostics.Contracts.Contract.EndContractBlock();

            if (buffer != null && (reader.Token != JsonToken.None && reader.Token != JsonToken.EndOfStream))
                reader.Value.CopyJsonTo(buffer);

            switch (reader.Token)
            {
                case JsonToken.None:
                case JsonToken.EndOfStream:
                case JsonToken.DateTime:
                case JsonToken.EndOfArray:
                case JsonToken.EndOfObject:
                case JsonToken.Number:
                case JsonToken.Member:
                case JsonToken.StringLiteral:
                case JsonToken.Null:
                    // returns True for primitives
                    return reader.Token == JsonToken.Boolean || reader.Token == JsonToken.DateTime || reader.Token == JsonToken.Number || reader.Token == JsonToken.StringLiteral || reader.Token == JsonToken.Null;
                case JsonToken.BeginArray:
                    reader.NextToken(); // advance

                    while (reader.Token != JsonToken.EndOfArray)
                    {
                        SkipValue(reader, buffer);
                        reader.NextToken(); // skip array member, and advance
                        if (reader.Token != JsonToken.EndOfArray)
                            buffer.Append(',');
                    }

                    SkipValue(reader, buffer); // skip ArrayEnd
                    break;
                case JsonToken.BeginObject:
                    reader.NextToken(); // advance
                    while (reader.Token != JsonToken.EndOfObject)
                    {
                        SkipValue(reader, buffer); reader.NextToken(); // skip member name, and advance
                        buffer.Append(':');
                        SkipValue(reader, buffer); reader.NextToken(); // skip member value, and advance
                        if (reader.Token != JsonToken.EndOfObject)
                            buffer.Append(',');
                    }
                    SkipValue(reader, buffer); // skip ObjectEnd
                    break;
            }

            return false;
        }
    }
}
